package com.micro.service.gateway.web.filter;


import com.micro.service.common.exception.ErrorCode;
import com.micro.service.gateway.util.WebUtil;
import com.micro.service.gateway.web.tps.DefaultTPSLimiter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 服务限流 处理
 * */
@Component
@Slf4j
public class TPSFilter implements Filter{

    private final DefaultTPSLimiter tpsLimiter = new DefaultTPSLimiter();

    private final ScheduledExecutorService executorService= Executors.newSingleThreadScheduledExecutor();

    public void setRate(int rate){
        tpsLimiter.setRate(rate);
    }

    @Override
    public void destroy() {
        executorService.shutdown();
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        //定义一个小时超时清除限流map中的会话URI
        executorService.scheduleAtFixedRate(() -> {

            tpsLimiter.timerClear();

            log.info("定时清除超过会话有效期的并发请求记录,stat size: {}", tpsLimiter.getStats().size());

        },0,30,TimeUnit.MINUTES);

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        
        HttpServletResponse response = (HttpServletResponse) resp;

        limitFilter(request, response, chain);

    }

    private void limitFilter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) throws IOException, ServletException {

        String sessionIdAndReqURI = req.getRequestedSessionId() + ":" + req.getRequestURI();

        if (!tpsLimiter.isAllowable(req)) {
            tpsLimiter.getStats().remove(sessionIdAndReqURI);
            log.error("请求sessionId:{} requestURI:{} 太过频繁",req.getRequestedSessionId(), req.getRequestURI());
            WebUtil.sendError(Integer.valueOf(ErrorCode.LIMITERR.getErrorCode()),ErrorCode.LIMITERR.getMessage(),resp);
            return;
        }

        chain.doFilter(req, resp);
    }
    
}
